﻿using Microsoft.Extensions.DependencyInjection;
using System;

namespace Sgr.Domain.Uow
{
    /// <summary>
    /// 默认工作单元管理器
    /// </summary>
    /// <remarks>
    /// 负责工作单元的创建、跟踪和生命周期管理。
    /// 支持嵌套工作单元和新工作单元的创建。
    /// </remarks>
    public class DefaultUnitOfWorkManager : IUnitOfWorkManager
    {
        /// <summary>
        /// 服务作用域工厂，用于创建新的服务作用域
        /// </summary>
        /// <remarks>
        /// 1. 作为单例服务存在，确保在整个应用程序中可以安全地创建作用域
        /// 2. 用于创建独立的服务范围，实现服务隔离
        /// 3. 每个工作单元都会获得自己的服务作用域
        /// </remarks>
        private readonly IServiceScopeFactory _serviceScopeFactory;

        /// <summary>
        /// 工作单元跟踪器
        /// </summary>
        private readonly IUnitOfWorkTracker _unitOfWorkTracker;

        /// <summary>
        /// 默认工作单元管理器
        /// </summary>
        /// <param name="unitOfWorkTracker">工作单元跟踪器</param>
        /// <param name="serviceScopeFactory">服务作用域工厂</param>
        /// <exception cref="ArgumentNullException"></exception>
        public DefaultUnitOfWorkManager(
            IUnitOfWorkTracker unitOfWorkTracker,
            IServiceScopeFactory serviceScopeFactory)
        {
            _unitOfWorkTracker = unitOfWorkTracker ?? throw new ArgumentNullException(nameof(unitOfWorkTracker));
            _serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
        }

        #region IUnitOfWorkManager

        /// <summary>
        /// 获取当前活动的工作单元
        /// </summary>
        public IUnitOfWork? Current => _unitOfWorkTracker.GetCurrentByChecking();

        /// <summary>
        /// 开始一个新的工作单元
        /// </summary>
        /// <param name="options">工作单元选项</param>
        /// <param name="requiresNew">是否需要创建新的工作单元，即使当前已存在工作单元</param>
        /// <returns>工作单元实例</returns>
        /// <exception cref="ArgumentNullException">当 options 参数为 null 时抛出</exception>
        public IUnitOfWork Begin(UnitOfWorkOption options, bool requiresNew = false)
        {
            Check.NotNull(options, nameof(options));

            var currentUow = Current;
            if (currentUow != null && !requiresNew)
            {
                return new ChildUnitOfWork(currentUow);
            }

            var unitOfWork = CreateNewUnitOfWork();
            unitOfWork.Initialize(options);

            return unitOfWork;
        }

        /// <summary>
        /// 创建新的工作单元
        /// </summary>
        /// <returns>新创建的工作单元实例</returns>
        /// <exception cref="InvalidOperationException">创建工作单元失败时抛出</exception>
        private IUnitOfWork CreateNewUnitOfWork()
        {
            // 使用单例的 IServiceScopeFactory 创建新的作用域
            var scope = _serviceScopeFactory.CreateScope();
            try
            {
                var outerUow = _unitOfWorkTracker.Current;

                // 在新作用域中解析服务
                var unitOfWork = scope.ServiceProvider.GetRequiredService<IUnitOfWork>();

                unitOfWork.SetOuter(outerUow);

                _unitOfWorkTracker.SetUnitOfWork(unitOfWork);

                // 确保作用域在工作单元释放时被正确处理
                unitOfWork.Disposed += (sender, args) =>
                {
                    _unitOfWorkTracker.SetUnitOfWork(outerUow);
                    // 释放作用域
                    scope.Dispose();
                };

                return unitOfWork;
            }
            catch
            {
                // 发生异常时确保作用域被释放
                scope.Dispose();
                throw;
            }
        }

        #endregion IUnitOfWorkManager
    }
}